在早期的很多程式語言裡並沒有例外事件的概念,我們可能會用錯誤碼或錯誤旗幟 (flag) 去捕捉例外狀況:
public class DeciceController {
...
public void sendShutDown() {
DeviceHandle handle = getHandle(DEV1);
// Check the state of the device
if (handle != DeviceHandle.INVALID) {
// Save the device status to the record field
retrieveDeviceRecord(handle);
// If not suspended, shut down
if (record.getStatus() != DEVICE_SUSPENDED) {
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
} else {
logger.log("Device suspended. Unable to shut down");
}
} else {
logger.log("Invalid handle for: "+ DEVI.toString());
}
}
...
}
我們可以很明顯的看出來,使用這樣的方法會使得程式碼變得雜亂。程式必須在呼叫結束後立即檢查錯誤並處理,而使用者除了很容易忽略這樣的檢查外,這也會導致深層巢狀結構。
也因此,較好的做法是,在你遇到一個錯誤的時候,拋出一個例外事件,如此,呼叫程式碼就會變得乾淨許多。錯誤處理的邏輯不該模糊原程式的邏輯。
讓我們將它修改成可偵測錯誤並拋出例外事件的程式碼:
public class DeciceController {
...
public void sendShutDown() {
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError {
DeviceHandle handle = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
}
private DeviceHandle getHandle(DeviceID id) {
...
throw new DeviceShutDownError("Invalid handle for: "+ DEVI.toString());
...
}
...
}
如此一來,原本糾纏在一起的兩件事被區分開來,程式將變得更乾淨和容易理解。
而每一個例外都應該要提供足夠的相關資訊,以便判斷發生了什麼樣的錯誤,其中包含了哪個操作發生錯誤、錯誤的型態是什麼。
錯誤處理對我來說是很陌生的一塊,之前除了串接 API 取得後端資料時會做錯誤處理,其餘程式碼基本上沒用過,這次藉著閱讀該篇章認真的學習了一回。看的仔細、收穫多,分享篇幅也就會長一點,所以明天還是會繼續關於錯誤處理的內容。